package org.spring.bean.factory;

import org.spring.bean.exceptions.BeansException;
import org.spring.bean.factory.config.ConfigurableBeanFactory;

/**
 * 用于访问 Spring bean 容器的根接口。
 * <p>
 * 这是 bean 容器的基本客户端视图；
 * {@link ListableBeanFactory} 和 {@link ConfigurableBeanFactory} 等其他接口可用于特定目的。
 * <p>
 * 该接口由包含许多 bean 定义的对象实现，每个定义由一个字符串名称唯一标识。
 * 根据 bean 定义，工厂将返回包含对象的独立实例（原型设计模式）或单个共享实例（单例设计模式的更好替代方案，其中实例是范围内的单例）工厂）。
 * 将返回哪种类型的实例取决于 bean 工厂配置：API 相同。
 * 从 Spring 2.0 开始，根据具体的应用程序上下文（例如 Web 环境中的“请求”和“会话”范围），可以使用更多范围。
 * <p>
 * 这种方法的要点是 BeanFactory 是应用程序组件的中央注册表，并集中了应用程序组件的配置（例如，单个对象不再需要读取属性文件）。
 * 有关这种方法的好处的讨论，请参阅“专家一对一 J2EE 设计和开发”的第 4 章和第 11 章。
 * <p>
 * 请注意，通常最好依靠依赖注入（“推”配置）通过设置器或构造器来配置应用程序对象，而不是使用任何形式的“拉”配置，如 BeanFactory 查找。
 * Spring 的依赖注入功能是使用这个 BeanFactory 接口及其子接口实现的。
 * <p>
 * 通常一个 BeanFactory 将加载存储在配置源（例如 XML 文档）中的 bean 定义，并使用 {@code org.springframework.beans} 包来配置 bean。
 * 但是，实现可以简单地返回它根据需要直接在 Java 代码中创建的 Java 对象。对如何存储定义没有限制：LDAP、RDBMS、XML、属性文件等。
 * 鼓励实现支持 bean 之间的引用（依赖注入）。
 * <p>
 * 与 {@link ListableBeanFactory} 中的方法不同，此接口中的所有操作也会检查父工厂是否为 {@link HierarchicalBeanFactory}。
 * 如果在该工厂实例中找不到 bean，则会询问直接父工厂。这个工厂实例中的 bean 应该覆盖任何父工厂中的同名 bean。
 * <p>
 * Bean 工厂实现应尽可能支持标准的 bean 生命周期接口。全套初始化方法及其标准顺序为：
 * <ol>
 * <li>BeanNameAware 的 {@code setBeanName}
 * <li>BeanClassLoaderAware 的 {@code setBeanClassLoader}
 * <li>BeanFactoryAware 的 {@code setBeanFactory}
 * <li>EnvironmentAware 的 {@code setEnvironment}
 * <li>EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
 * <li>ResourceLoaderAware's {@code setResourceLoader} (仅适用于在应用程序上下文中运行时)
 * <li>ApplicationEventPublisherAware's {@code setApplicationEventPublisher} (仅适用于在应用程序上下文中运行时)
 * <li>MessageSourceAware's {@code setMessageSource} (仅适用于在应用程序上下文中运行时)
 * <li>ApplicationContextAware's {@code setApplicationContext} (仅适用于在应用程序上下文中运行时)
 * <li>ServletContextAware's {@code setServletContext} (仅适用于在 Web 应用程序上下文中运行时)
 * <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors
 * <li>InitializingBean's {@code afterPropertiesSet} (自定义初始化方法定义)
 * <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors
 * </ol>
 *
 * <p>在关闭 bean 工厂时，将应用以下生命周期方法：
 * <ol>
 * <li>{@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors
 * <li>DisposableBean's {@code destroy}
 * <li>a custom destroy-method definition
 * </ol>
 *
 * @author 李坤
 * @date 2022/4/13 15:43
 */
public interface BeanFactory {

    /**
     * 返回指定 bean 的一个实例，该实例可以是共享的，也可以是独立的。
     * <p>
     * 此方法允许将 Spring BeanFactory 用作 Singleton 或 Prototype 设计模式的替代品。
     * 在 Singleton bean 的情况下，调用者可以保留对返回对象的引用。
     * <p>
     * 将别名转换回相应的规范 bean 名称。
     * <p>
     * 如果在此工厂实例中找不到 bean，将询问父工厂。
     *
     * @param name 要检索的 bean 的名称
     *
     * @return bean 的一个实例
     *
     * @throws BeansException 如果无法获得 bean
     */
    Object getBean(String name) throws BeansException;

    /**
     * 返回指定 bean 的一个实例，该实例可以是共享的，也可以是独立的。
     * <p>
     * 允许指定显式构造函数参数工厂方法参数，覆盖 bean 定义中指定的默认参数（如果有）。
     *
     * @param name 要检索的 bean 的名称
     * @param args 使用显式参数创建 bean 实例时使用的参数（仅在创建新实例而不是检索现有实例时应用）
     *
     * @return bean 的一个实例
     *
     * @throws NoSuchBeanDefinitionException 如果没有这样的bean定义
     * @throws BeansException                如果无法创建 bean
     * @since 2.5
     */
    Object getBean(String name, Object... args) throws BeansException;

    /**
     * 返回指定 bean 的一个实例，该实例可以是共享的，也可以是独立的。
     * <p>
     * 行为与 {@link #getBean(String)} 相同，但如果 bean 不是所需类型，则通过抛出 BeanNotOfRequiredTypeException 来提供类型安全度量。
     * 这意味着无法在正确转换结果时抛出 ClassCastException，就像 {@link #getBean(String)} 可能发生的那样。
     * <p>
     * 将别名转换回相应的规范 bean 名称。
     * <p>
     * 如果在此工厂实例中找不到 bean，将询问父工厂。
     *
     * @param name         要检索的 bean 的名称
     * @param requiredType bean 必须匹配的类型；可以是接口或超类
     *
     * @return bean 的一个实例
     *
     * @throws BeansException 如果无法创建 bean
     */
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;

}
